<?php
/**
 *
 * Copyright  FaShop
 * License    http://www.fashop.cn
 * link       http://www.fashop.cn
 * Created by FaShop.
 * User: hanwenbo
 * Date: 2017/11/21
 * Time: 上午11:03
 *
 */

namespace ezswoole;

use EasySwoole\EasySwoole\Config as AppConfig;
use EasySwoole\Http\AbstractInterface\Controller as AbstractController;
use EasySwoole\Spl\SplArray;
use ezswoole\utils\ParamsSet;
use Rakit\Validation\Validator as RakitValidator;

abstract class Controller extends AbstractController
{
	protected $app;
	protected $post;
	protected $get;
	/**
	 * @var Request
	 */
	protected $request;
	// 验证失败是否抛出异常
	protected $failException = false;
	// 是否批量验证
	protected $batchValidator = false;
	private $validator;

	public function index()
	{
		return $this->send( - 1, [], "NOT FOUND" );
	}

	protected function onRequest( $actionName ) : ?bool
	{
		$this->request = new Request( $this->request() );
		$this->get     = $this->request->get() ? new SplArray( $this->request->get() ) : null;
		$this->post    = $this->request->post() ? new SplArray( $this->request->post() ) : null;
		return null;
	}

	protected function router()
	{
		return $this->send( - 1, [], "your router not end" );
	}

	protected function send( $code = 0, $data = [], $message = null ) : bool
	{
		// todo 废除
		$this->response()->withAddedHeader( 'Access-Control-Allow-Origin', AppConfig::getInstance()->getConf( 'response.access_control_allow_origin' ) );
		$this->response()->withAddedHeader( 'Content-Type', 'application/json; charset=utf-8' );
		$this->response()->withAddedHeader( 'Access-Control-Allow-Headers', AppConfig::getInstance()->getConf( 'response.access_control_allow_headers' ) );
		$this->response()->withAddedHeader( 'Access-Control-Allow-Methods', AppConfig::getInstance()->getConf( 'response.access_control_allow_methods' ) );
		$this->response()->withStatus( 200 );
		$content = [
			"code"   => $code,
			"result" => $data,
			"msg"    => $message,
		];
		$this->response()->write( json_encode( $content, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) );
		return true;
	}

	protected function getPageLimit() : array
	{
		$param = $this->request->param();
		$page  = isset( $param['page'] ) ? (int)$param['page'] : 1;
		$rows  = isset( $param['rows'] ) ? (int)$param['rows'] : 10;
		return [$page, $rows];

	}

	/**
	 * 设置验证失败后是否抛出异常
	 * @param bool $fail
	 * @return Controller
	 */
	protected function validatorFailException( $fail = true ) : Controller
	{
		$this->failException = $fail;
		return $this;
	}

	/**
	 * 验证数据
	 * @param array          $data
	 * @param array | string $validator
	 * @param array |string  $message
	 * @param bool           $batch
	 * @param null           $callback
	 * @throw null
	 * @return array|bool
	 */
	protected function validator( $data, $validator, $message = [], bool $batch = false, $callback = null )
	{
		if( is_string( $validator ) && is_string( $message ) ){
			$class = $validator;
			$scene = $message;
			if( class_exists( $class ) ){
				$v = new $class;
			} else{
				\EasySwoole\EasySwoole\Logger::getInstance()->log( 'class not exists:'.$class, 'error' );
				return false;
			}
			if( !empty( $scene ) ){
				$v->scene( $scene );
			}
		} else{
			if( is_array( $validator ) ){
				$v = new Validator();
				$v->rule( $validator );
			} else{
				if( strpos( $validator, '.' ) ){
					[$validator, $scene] = explode( '.', $validator );
				}
				$class = "\App\Validator\\".str_replace( "/", "\\", $validator );
				if( class_exists( $class ) ){
					$v = new $class;
				} else{
					\EasySwoole\EasySwoole\Logger::getInstance()->log( 'class not exists:'.$class, 'error' );
					return false;
				}
				if( !empty( $scene ) ){
					$v->scene( $scene );
				}
			}
		}


		// 是否批量验证
		if( $batch || $this->batchValidator ){
			$v->batch( true );
		}

		if( is_array( $message ) ){
			$v->message( $message );
		}
		if( $callback && is_callable( $callback ) ){
			call_user_func_array( $callback, [$v, &$data] );
		}
		if( !$v->check( $data ) ){
			if( $this->failException ){
				return $v->getError();
			} else{
				$this->setValidator( $v );
				return $v->getError();
			}
		} else{
			return true;
		}
	}

	protected function getValidator() : Validator
	{
		return $this->validator;
	}

	protected function setValidator( Validator $instance ) : void
	{
		$this->validator = $instance;
	}

	/**
	 * @param array $params
	 * @param array $allowdFields
	 * @return array|utils\ParamsSet
	 */
	protected function getParamsSet( array $params, array $allowdFields ) : ParamsSet
	{
		return new \ezswoole\utils\ParamsSet( $params, $allowdFields );
	}

	protected function getValidFirstMessage( $obj )
	{
		foreach( $obj as $err ){
			if( is_string( $err ) ){
				return $err;
			}

			if( is_array( $err ) ){
				return $this->getValidFirstMessage( $err );
			}
			break;
		}
		return '未知';
	}

	public function valid( array $rules = [], array $messages = [] )
	{
		$validator = new RakitValidator;
		$post      = (array)$this->request->post();
		$get       = (array)$this->request->get();
		$file      = (array)$this->request->file();
		$params    = $post + $get + $file; // post内参数优先级高

		// TODO 默认语言包
		$defaultMessages = [
			//			'required' => ':attribute harus diisi',
			//			'email'    => ':email tidak valid',
		];
		$_messages       = array_unique( $messages + $defaultMessages );
		$validation      = $validator->validate( $params, $rules, $_messages );

		if( $validation->fails() ){
			$errors = $validation->errors();
			$errObj = $errors->firstOfAll();
			$msg    = $this->getValidFirstMessage( $errObj );
			throw new \Exception( $msg );
		} else{
			return $validation->getValidData();
		}
	}
}